package com.zaizai.interceptor;
import com.zaizai.exception.LoginException;
import com.zaizai.properties.JwtProperties;
import com.zaizai.utils.BaseContext;
import com.zaizai.utils.JwtUtil;
import org.springframework.data.redis.core.StringRedisTemplate;

import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.lang.NonNull;
/*
 * jwt令牌校验的拦截器

 */


@Component
@Slf4j
public class JwtTokenInterceptor implements HandlerInterceptor {
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 校验JWT令牌
     *
     * @param request  请求对象
     * @param response 响应对象
     * @param handler  处理对象
     * @return 是否允许请求继续
     * @throws Exception 异常处理
    */

    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
        // 如果是OPTIONS请求，直接放行
        if (request.getMethod().equals("OPTIONS")) {
            return true;
        }

        String token = request.getHeader("Authorization");
        if (token != null) {
            try {

                // 验证token
                Claims claims = JwtUtil.parseJWT(jwtProperties.getSecretKey(), token);
                
                // 从 claims 中获取用户 ID，使用 Number 类型
                Number userId = claims.get("id", Number.class);
                if (userId == null) {
                    log.error("Token中未包含用户ID");
                    response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                    return false;
                }
                // 4. 从Redis中获取存储的Token
            String tokenRedis = stringRedisTemplate.opsForValue().get("login:" + userId);
            if (tokenRedis == null) {
                log.error("用户的登录信息未在Redis中找到");
                throw new LoginException("登录已失效，请重新登录！");
            }

            // 5. 校验令牌是否一致
            if (!token.equals(tokenRedis)) {
                log.error("Token不一致，可能是重新登录");
                throw new LoginException("登录已失效，请重新登录！");
            }
                // 将用户信息存入ThreadLocal
                BaseContext.setCurrentId(userId.longValue());
                return true;
            } catch (Exception e) {
                log.error("Token验证失败: ", e);
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                return false;
            }
        }
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        return false;
    }
}
